---
title: Style props
description: Build UIs quickly by passing css properties as "props" to your components.
---

While you can get very far by using the `className` prop and function from Panda, style props provide a more ergonomic
way of expressing styles.

Panda will extract the style props through static analysis and generate the CSS at build time.

> If you use Chakra UI, Styled System, or Theme UI, you'll feel right at home right away 😊

```jsx
import { css } from '../styled-system/css'
import { styled } from '../styled-system/jsx'

// The className approach
const Button = ({ children }) => (
  <button
    className={css({
      bg: 'blue.500',
      color: 'white',
      py: '2',
      px: '4',
      rounded: 'md'
    })}
  >
    {children}
  </button>
)

// The style props approach
const Button = ({ children }) => (
  <styled.button bg="blue.500" color="white" py="2" px="4" rounded="md">
    {children}
  </styled.button>
)
```

## Configure JSX

Using JSX style props is turned off by default in Panda, but you can opt-in to this feature by using the `jsxFramework`
property in the panda config.

> ⚠️ Panda will not extract style props from JSX elements if you don't set the `jsxFramework` property. This is to avoid
> unnecessary work for projects that don't use JSX.

### Choose Framework

JSX is a JavaScript syntax extension that allows you to write HTML-like code directly within your JavaScript code and is
supported by most popular frameworks. Panda supports JSX style props in React, Preact, Vue 3, Qwik and Solid.js.

```js filename="panda.config.ts"
import { defineConfig } from '@pandacss/dev'

export default defineConfig({
  // ...
  jsxFramework: 'react'
})
```

### Generate JSX runtime

Next, you need to run `panda codegen` to generate the JSX runtime for your framework.

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
  {/* <!-- prettier-ignore-start --> */}
  <Tab>
  ```bash
  pnpm panda codegen --clean
  ```
  </Tab>
  <Tab>
  ```bash
  npm panda codegen --clean
  ```
  </Tab>
  <Tab>
  ```bash
  yarn panda codegen --clean
  ```
  </Tab>
  <Tab>
  ```bash
  bun panda codegen --clean
  ```
  </Tab>
  {/* <!-- prettier-ignore-end --> */}
</Tabs>

That's it! You can now use JSX style props in your components.

## Using Style Props

### JSX Element

Style props are just CSS properties that you can pass to your components as props. With the JSX runtime, you can use
`styled.<element>` syntax to create supercharged JSX elements that support style props.

```jsx
import { styled } from '../styled-system/jsx'

const Button = ({ children }) => (
  <styled.button bg="blue.500" color="white" py="2" px="4" rounded="md">
    {children}
  </styled.button>
)
```

### Property Renaming

<Callout type="warning">Due to the static nature of Panda, you can't rename properties at runtime.</Callout>

```tsx filename="App.tsx"
import { Circle, CircleProps } from '../styled-system/jsx'

type Props = {
  circleSize?: CircleProps['size']
}

const CustomCircle = (props: Props) => {
  const { circleSize = '3' } = props
  return (
    <Circle
      // ❌ Avoid: Panda can't know that you're mapping `circleSize` to `size`
      size={circleSize}
    />
  )
}

// ...

const App = () => {
  return (
    // In this case, you should keep the `size` naming
    <CustomCircle circleSize="4" />
  )
}
```

The same principles apply to all style props, recipe variants, and pattern props.

<Callout type="info">
  If you still need to rename properties at runtime, you can use `config.staticCss` as an escape-hatch to pre-generate
  the CSS anyway for the properties you need.
</Callout>

### Recipe

You can use recipe variants as JSX props to quickly change the styles of your components, as long as
[you're tracking those components in your recipe config](/docs/concepts/recipes#advanced-jsx-tracking).

```tsx
import { styled } from '../styled-system/jsx'
import { button, type ButtonVariantProps } from '../styled-system/recipes'

const Button = (props: ButtonVariantProps) => <button className={button(props)}>Button</button>

const App = () => <Button variant="secondary">Button</Button>
```

## Factory Function

You can also use the `styled` function to create a styled component from any component or JSX intrinsic element (like
"a", "button").

```jsx
import { styled } from '../styled-system/jsx'
import { Button } from 'component-library'

const StyledButton = styled(Button)

const App = () => (
  <StyledButton bg="blue.500" color="white" py="2" px="4" rounded="md">
    Button
  </StyledButton>
)
```

> You can configure the `styled` function name using the [`config.jsxFactory`](/docs/references/config#jsxfactory)
> option.

### Factory Recipe

You can define a recipe for your component using the `styled` function. This is useful when you want to create a
component that has a specific set of style props.

```jsx
import { styled } from '../styled-system/jsx'

const Button = styled('button', {
  base: {
    py: '2',
    px: '4',
    rounded: 'md'
  },
  variants: {
    variant: {
      primary: {
        bg: 'blue.500',
        color: 'white'
      },
      secondary: {
        bg: 'gray.500',
        color: 'white'
      }
    }
  }
})

const App = () => (
  <Button variant="secondary" mt="10px">
    Button
  </Button>
)
```

### Factory Options

There's a few options you can pass to the `styled` function to customize the behavior of the generated component.

```ts
interface FactoryOptions<TProps extends Dict> {
  dataAttr?: boolean
  defaultProps?: TProps
  shouldForwardProp?(prop: string, variantKeys: string[]): boolean
}
```

#### `dataAttr`

Setting `dataAttr` to true will add a `data-recipe="{recipeName}"` attribute to the element with the recipe name. This
is useful for testing and debugging.

```jsx
import { styled } from '../styled-system/jsx'
import { button } from '../styled-system/recipes'

const Button = styled('button', button, { dataAttr: true })

const App = () => <Button variant="secondary">Button</Button>
// => <button data-recipe="button" class="btn btn--variant_purple">Button</button>
```

#### `defaultProps`

allows you to skip writing wrapper components just to set a few props. It also allows you to locall override the default
variants or base styles of a recipe.

```jsx
import { styled } from '../styled-system/jsx'
import { button } from '../styled-system/recipes'

const Button = styled('button', button, {
  defaultProps: {
    variant: 'secondary',
    px: '10px'
  }
})

const App = () => <Button>Button</Button>
// => <button class="btn btn--variant_secondary px_10px">Button</button>
```

#### `shouldForwardProp`

Used to customize which props are forwarded to the underlying element. By default, all props except recipe variants and
style props are forwarded.

For example, you could use it to integrate with [Framer Motion](https://www.framer.com/motion/).

```jsx
import { styled } from '../styled-system/jsx'
import { button } from '../styled-system/recipes'
import { motion, isValidMotionProp } from 'framer-motion'

const StyledMotion = styled(
  motion.div,
  {},
  {
    shouldForwardProp: (prop, variantKeys) =>
      isValidMotionProp(prop) || (!variantKeys.includes(prop) && !isCssProperty(prop))
  }
)
```

### Unstyled prop

All styled components accept an `unstyled` prop that allows you to disable the recipe styles. This is useful when you
want to use a component's structure but apply completely custom styling.

```jsx
import { styled } from '../styled-system/jsx'
import { button } from '../styled-system/recipes'

const Button = styled('button', button)

const App = () => (
  <>
    {/* With recipe styles */}
    <Button>Styled Button</Button>

    {/* Without recipe styles, but inline styles still work */}
    <Button unstyled bg="red.500" color="white">
      Unstyled Button
    </Button>
  </>
)
```

### Reducing the allowed style props

You can reduce the allowed JSX properties on the factory using
[`config.jsxStyleProps`](/docs/references/config#jsxstyleprops):

- When set to 'all', all style props are allowed.
- When set to 'minimal', only the `css` prop is allowed.
- When set to 'none', no style props are allowed and therefore the `jsxFactory` will not be usable as a component:
  - `<styled.div />` and `styled("div")` aren't valid
  - but the recipe usage is still valid `styled("div", { base: { color: "red.300" }, variants: { ...} })`

> Removing style props (from `all` to either `minimal` or `none`) will reduce the size of the generated code due to not
> having to check which props are style props at runtime.

## JSX Patterns

Patterns are common layout patterns like `stack`, `grid`, `circle` that can be used to speed up your css. Think of them
as a way to avoid repetitive layout styles.

All the patterns provided by Panda are available as JSX components.

> Learn more about the [patterns](/docs/customization/patterns) we provide.

```jsx
import { Stack, Circle } from '../styled-system/jsx'

const App = () => (
  <Stack gap="4" align="flex-start">
    <button>Button</button>
    <Circle size="4" bg="red.300">
      4
    </Circle>
  </Stack>
)
```

## Making your own styled components

To make a custom JSX component that accepts style props, Use the `splitCssProps` function to split style props from
other component props.

> For this to work correctly, set the `jsxFramework` to the framework you're using in your panda config.

```tsx
import { splitCssProps } from '../styled-system/jsx'
import type { HTMLStyledProps } from '../styled-system/types'

export function Component(props: HTMLStyledProps<'div'>) {
  const [cssProps, restProps] = splitCssProps(props)
  const { css: cssProp, ...styleProps } = cssProps

  const className = css({ display: 'flex', height: '20', width: '20' }, styleProps, cssProp)

  return <div {...restProps} className={className} />
}

// Usage
function App() {
  return <Component w="2">Click me</Component>
}
```

## TypeScript

Panda provides type definitions for all the style props that are supported by the JSX runtime.

You can use these types to get type safety in your components.

### Style Object

Use the `JsxStyleProps` to get the types of the style object that is compatible with JSX elements.

```tsx
import { styled } from '../styled-system/jsx'
import type { JsxStyleProps } from '../styled-system/types'

interface ButtonProps {
  color?: JsxStyleProps['color']
}

const Button = (props: ButtonProps) => {
  return <styled.button {...props}>
}
```

### Style Props

Use the `HTMLStyledProps` type to get the types of an element in addition to the style props.

```tsx {2}
import { styled } from '../styled-system/jsx'
import type { HTMLStyledProps } from '../styled-system/jsx'

type ButtonProps = HTMLStyledProps<'button'>

const Button = (props: ButtonProps) => {
  return <styled.button {...props}>
}
```

### Variant Props

Use the `StyledVariantProps` type to extract the variants from a styled component.

```tsx {2}
import { styled } from '../styled-system/jsx'
import type { StyledVariantProps } from '../styled-system/jsx'

const Button = styled('button', {
  base: { color: 'black' },
  variants: {
    state: {
      error: { color: 'red' },
      success: { color: 'green' }
    }
  }
})

type ButtonVariantProps = StyledVariantProps<typeof Button>
//   ^ { state?: 'error' | 'success' | undefined }
```

### Patterns

Every pattern provided by Panda has a corresponding type that you can use to get type safety in your components.

```tsx {2}
import { Stack } from '../styled-system/jsx'
import type { StackProps } from '../styled-system/jsx'
```
